#ifndef FATDRIVER_H
#define FATDRIVER_H

// easy types
typedef unsigned char uchar_t;
typedef unsigned short ushort_t;
typedef unsigned int uint_t;

// Directory entry types
#define ATTR_READ_ONLY		0x01
#define ATTR_HIDDEN			0x02
#define ATTR_SYSTEM			0x04
#define ATTR_VOLUME_ID		0x08
#define ATTR_DIRECTORY		0x10
#define ATTR_ARCHIVE		0x20
#define ATTR_LONG_NAME		( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID )
#define ATTR_LONG_NAME_MASK	( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_DIRECTORY | ATTR_ARCHIVE )

// Long directory entry defines
#define LAST_LONG_ENTRY		0x40

// boot parameter block for all FAT filesystems
struct BPB_FAT
{
	uchar_t		BS_jmpBoot[3];
	uchar_t		BS_OEMName[8];
	ushort_t	BPB_BytsPerSec;
	uchar_t		BPB_SecPerClus;
	ushort_t	BPB_RsvdSecCnt;
	uchar_t		BPB_NumFATs;
	ushort_t	BPB_RootEntCnt;
	ushort_t	BPB_TotSec16;
	uchar_t		BPB_Media;
	ushort_t	BPB_FATSz16;
	ushort_t	BPB_SecPerTrk;
	ushort_t	BPB_NumHeads;
	uint_t		BPB_HiddSec;
	uint_t		BPB_TotSec32;
} __attribute((packed));

// FAT32 BPB starting at offset 36
struct BPB_FAT32
{
	uint_t		BPB_FATSz32;
	ushort_t	BPB_ExtFlags;
	ushort_t	BPB_FsVer;
	uint_t		BPB_RootClus;
	ushort_t	BPB_FsInfo;
	ushort_t	BPB_BkBootSec;
	uchar_t		BPB_Reserved[12];
	uchar_t		BS_DrvNum;
	uchar_t		BS_Reserved1;
	uchar_t		BS_BootSig;
	uint_t		BS_VolID;
	uchar_t		BS_VolLab[11];
	uchar_t		BS_FilSysType[8];
} __attribute((packed));

// FAT32 directory entry
struct FAT32_DirEnt {
	uchar_t		DIR_Name[11];
	uchar_t		DIR_Attr;
	uchar_t		DIR_NTRes;
	uchar_t		DIR_CrtTimeTenth;
	ushort_t	DIR_CrtTime;
	ushort_t	DIR_CrtDate;
	ushort_t	DIR_LstAccDate;
	ushort_t	DIR_FstClusHI;
	ushort_t	DIR_WrtTime;
	ushort_t	DIR_WrtDate;
	ushort_t	DIR_FstClusLO;
	uint_t		DIR_FileSize;
};

// an internal file descriptor
typedef struct {
	uint_t dev; // the device id (ie. 0 = dr0)
	uint_t devdesc; // the device descriptor (for read/write)
	uint_t dirsect; // the directory sector in which this file is found
	uint_t diroffset; // the directory offset of this entry
	struct FAT32_DirEnt myDirEnt; // the directory entry
	
	uint_t DataStart; // the start of the data area
	uint_t RootDirCount; // sectors in the root directory
} fat32_filedesc;

// FAT32 open function
int fat32_open( fat32_filedesc* fd, struct BPB_FAT bpb, struct BPB_FAT32 bpb32, char* fn );

// FAT32 read function
int fat32_read( fat32_filedesc* fd, struct BPB_FAT bpb, struct BPB_FAT32 bpb32, int offset, int count, char* buff );

// FAT32 write function
int fat32_write( fat32_filedesc* fd, struct BPB_FAT bpb, struct BPB_FAT32 bpb32, int offset, int count, char* buff );

#endif
